﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;
using System.Diagnostics;

namespace CSharpUi_ServerShell
{
    public partial class FrmServer : Form
    {
        Process mp_Polipo = new Process();
        Process mp_Tunnel = new Process();

        #region 和进程状态有关的定义
        /// <summary>
        /// 外部进程的运行状态。 讨论0912-1315:是否有 Failed 等状态存在?
        /// </summary>
        private enum Enum_ProcessStauts
        {
            Running,
            Stopped,
        }
        private Enum_ProcessStauts me_PolipStatus = Enum_ProcessStauts.Stopped;
        private Enum_ProcessStauts me_TunnelStatus = Enum_ProcessStauts.Stopped; 
        #endregion

        
        public FrmServer()
        {
            InitializeComponent();
        }

        #region 启动和关闭外部进程，混杂了一些和界面有关的代码。下一步：纯净化
        private void mm_LaunchPolipo()
        {
            mp_Polipo.StartInfo.FileName = "polipo.exe";
            mp_Polipo.StartInfo.Arguments = " -c NUL proxyAddress=" + txtPolipoIp.Text
                                    + " proxyPort=" + txtPolipoPort.Text;


            if (chkShowConsole.Checked)
            {
                mp_Polipo.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
                mp_Polipo.StartInfo.CreateNoWindow = false;
            }
            else
            {
                mp_Polipo.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                mp_Polipo.StartInfo.CreateNoWindow = true;
            }

            mp_Polipo.StartInfo.UseShellExecute = false;
            mp_Polipo.StartInfo.RedirectStandardOutput = true;
            mp_Polipo.StartInfo.RedirectStandardError = true;
            mp_Polipo.StartInfo.RedirectStandardInput = true;
            //mo_PolipoReader = mp_Polipo.StandardOutput;

            if (mp_Polipo.Start())
            {
                //启动成功
                //做些线程的准备，然后启动线程
                mo_PolipoOutputReader = mp_Polipo.StandardOutput;
                mo_PolipoErrorReader  = mp_Polipo.StandardError;
                mo_ThreadPolipo = new Thread(mm_AnsyReadPolipoOutput);
                mo_ThreadPolipo.Start();
                Thread ooErrorReader = new Thread(mm_AnsyReadPolipoError);
                ooErrorReader.Start();
                me_PolipStatus = Enum_ProcessStauts.Running;

            }
            else
            {
                //启动失败
                me_PolipStatus = Enum_ProcessStauts.Stopped;
            }

        }
        private void mm_LaunchTunnelServer()
        {
            #region From document
            //-c              client mode 以客户端方式运行（默认模式）
            //-s              server mode 以服务端方式运行
            //-l              listen port 监听的端口号
            //-i              connect ip address 连接的ip地址
            //-p              connect port 连接的端口号
            //-w              band width limit(Byte/s) 带宽的限制（默认102400）
            //-b              bind hostname 绑定的主机名
            //-k              serect key 密钥
            // encryptedtunnel -s -l 12345 -i 1.1.1.1 -p 1111 -w 10240
            #endregion
            mp_Tunnel.StartInfo.FileName = "encryptedtunnel.exe";//需要启动的程序名       
            //arg=["encryptedtunnel","-s","-l",port,"-i",phost,"-p",pport,"-w",bw]
            mp_Tunnel.StartInfo.Arguments = "-s "
                                    + " -l " + txtServerPort.Text
                                    + " -i " + cbbServerIp.Text
                                    + " -p " + txtPolipoPort.Text
                                    + " -w " + "102400";

            #region 一个测试的例子
            //mp_Tunnel.StartInfo.FileName = "ping.exe";
            //mp_Tunnel.StartInfo.Arguments = " 192.168.1.1 -t";
            #endregion


            if (chkShowConsole.Checked)
            {
                mp_Tunnel.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
                mp_Tunnel.StartInfo.CreateNoWindow = false;
            }
            else
            {
                mp_Tunnel.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                mp_Tunnel.StartInfo.CreateNoWindow = true;
            }

            mp_Tunnel.StartInfo.UseShellExecute = false;
            mp_Tunnel.StartInfo.RedirectStandardOutput = true;
            mp_Tunnel.StartInfo.RedirectStandardError = true;

            if (mp_Tunnel.Start())
            {
                //启动成功。注意：这里不是做的语法分析。在Tunnel升级之后，可能会得到错误的KEY
                mo_TunnelOutputReader = mp_Tunnel.StandardOutput;//截取输出流
                mo_TunnelErrorReader = mp_Tunnel.StandardError;  //截取错误流
                string line = mo_TunnelOutputReader.ReadLine();//每次读取一行
                string line2 = mo_TunnelOutputReader.ReadLine();//每次读取一行
                txtServerSecretKey.Text = line2.Replace("INFO:", "");
                //把固定的输出写到 txtTunnel中。
                txtTunnelOutput.AppendText(line + System.Environment.NewLine);
                txtTunnelOutput.AppendText(line2 + System.Environment.NewLine);


                if (chkCopyKeyAutomatic.Checked)
                {
                    Clipboard.SetText(txtServerSecretKey.Text);
                }
                //做些线程的准备，然后启动线程
                mo_ThreadTunnel = new Thread(mm_AnsyReadTunnelOutput);
                mo_ThreadTunnel.Start();
                Thread ooThreadTunnelError = new Thread(mm_AnsyReadTunnelError);
                ooThreadTunnelError.Start();
                //所有的工作都结束了，更新状态吧    
                me_TunnelStatus = Enum_ProcessStauts.Running;

            }
            else
            {
                //启动失败
                me_TunnelStatus = Enum_ProcessStauts.Stopped;
            }

        }
        /// <summary>
        /// 关闭进程，在Stop,FormClosed 的时候被调用。
        /// </summary>
        private void mm_KillProcessed()
        {
            if (me_PolipStatus == Enum_ProcessStauts.Running)
            {
                mp_Polipo.Kill();
                mp_Polipo.Close();
                me_PolipStatus = Enum_ProcessStauts.Stopped;

            }
            if (me_TunnelStatus == Enum_ProcessStauts.Running)
            {
                mp_Tunnel.Kill();
                mp_Tunnel.Close();
                me_TunnelStatus = Enum_ProcessStauts.Stopped;
            }

        } 
        #endregion

        #region 读取外部进程的标准输出，并且回写到界面中。因为是多线程，所以代码很罗嗦。注意：还没写关闭线程。
        StreamReader mo_TunnelOutputReader;
        StreamReader mo_TunnelErrorReader;
        StreamReader mo_PolipoOutputReader;
        StreamReader mo_PolipoErrorReader;
        Thread mo_ThreadTunnel;
        Thread mo_ThreadPolipo;

        

        delegate void SetTextCallback_TextBox(TextBox ooTarget, string text);
        delegate void SetTextCallBack_Label(Label ooTarget, string ssText);
        delegate void SetTextCallBack_Button(Button  ooTarget, string ssText);
        

        private void mm_AnsyCopyToTextBox(TextBox ooTarget, string ssText)
        {
            if (ooTarget.InvokeRequired)
            {
                SetTextCallback_TextBox d = new SetTextCallback_TextBox(mm_AnsyCopyToTextBox);
                this.Invoke(d, ooTarget, ssText);
            }
            else
            {
                ooTarget.AppendText(ssText  + System.Environment.NewLine);
            }
        }
        private void mm_AnsyCopyToLabel(Label ooTarget, string ssText)
        {
            if (ooTarget.InvokeRequired)
            {
                SetTextCallBack_Label d = new SetTextCallBack_Label(mm_AnsyCopyToLabel);
                this.Invoke(d, ooTarget, ssText);
            }
            else
            {
                ooTarget.Text = ssText + System.Environment.NewLine;
            }
        }
        private void mm_AnsyCopyToButton(Button ooTarget, string ssText)
        {
            if (ooTarget.InvokeRequired)
            {
                SetTextCallBack_Button d = new SetTextCallBack_Button(mm_AnsyCopyToButton);
                this.Invoke(d, ooTarget, ssText);
            }
            else
            {
                ooTarget.Text = ssText + System.Environment.NewLine;
            }
        }
        
        /// <summary>
        /// 注意：这是一个独立的线程。
        /// 下一版本：在合适的地方终止线程。
        /// </summary>
        private void mm_AnsyReadTunnelOutput()
        {
    
                while (!mo_TunnelOutputReader.EndOfStream)
                {
                    string line = mo_TunnelOutputReader.ReadLine();//每次读取一行
                    //mm_AnsySetTunnelText(line);
                    mm_AnsyCopyToTextBox(txtTunnelOutput, line);
                }
        }
        private void mm_AnsyReadTunnelError()
        {
            while (!mo_TunnelErrorReader.EndOfStream)
            {
                string line = mo_TunnelErrorReader.ReadLine();//每次读取一行
                mm_AnsyCopyToTextBox(txtTurnnelError, line);
            }
        }
        private void mm_AnsyReadPolipoOutput()
        {
            while (!mo_PolipoOutputReader.EndOfStream)
            {
                string line = mo_PolipoOutputReader.ReadLine();//每次读取一行
                mm_AnsyCopyToTextBox(txtTunnelOutput, line);
            }

        }
        private void mm_AnsyReadPolipoError()
        {
            while (!mo_PolipoErrorReader.EndOfStream)
            {
                string line = mo_PolipoErrorReader.ReadLine();//每次读取一行
                mm_AnsyCopyToTextBox(txtPolipoError, line);
            }
        }
        
        #endregion


        #region 界面事件的响应
        private void FrmServer_Load(object sender, EventArgs e)
        {
            //获取所有的网卡的IP,填写到 cbbServerIp中
            foreach (IPAddress item in Dns.GetHostByName(Dns.GetHostName()).AddressList)
            {
                cbbServerIp.Items.Add(item.ToString());
            }
            //第一个获得的地址有效
            cbbServerIp.SelectedIndex = 0;

            ooMonitor = new Thread(mm_AnsyMonitor);
            
        }
        private void FrmServer_FormClosed(object sender, FormClosedEventArgs e)
        {
            mm_KillProcessed();
        }
        Thread ooMonitor;

        /// <summary>
        /// 更新界面的显示。目前仅包含 Status
        /// </summary>
        private void mm_UpdateUi()
        {
            mm_AnsyCopyToLabel(lblPolipoStatus, me_PolipStatus.ToString());
            mm_AnsyCopyToLabel(lblTunnelStatus, me_TunnelStatus.ToString());
            //------------------------------------------------------------------------
            if (me_PolipStatus == Enum_ProcessStauts.Running && me_TunnelStatus == Enum_ProcessStauts.Running)
            {
                mm_AnsyCopyToButton (btnLauch, "Stop");
            }
            else
            {
                mm_AnsyCopyToButton(btnLauch, "Launch");
            }

        }
        private void btnCopyKey_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(txtServerSecretKey.Text);
        }
        private void btnLauch_Click(object sender, EventArgs e)
        {

            if (me_PolipStatus == Enum_ProcessStauts.Stopped && me_TunnelStatus == Enum_ProcessStauts.Stopped)
            {
                //已经停止，现在开始运行。
                mm_LaunchPolipo();
                mm_LaunchTunnelServer();
                
            }
            else if (me_PolipStatus == Enum_ProcessStauts.Running && me_TunnelStatus == Enum_ProcessStauts.Running)
            {
                //已经运行，现在停止。
                mm_KillProcessed();
                
            }
            else if (me_PolipStatus == Enum_ProcessStauts.Stopped)
            {
                //一个运行，一个在停止。默认为启动之
                mm_LaunchPolipo();
            }
            else
            {
                //一个运行，一个在停止。默认为启动之
                mm_LaunchTunnelServer();
            }
            
            this.Focus();
            mm_UpdateUi();
        }
        private void btnShowDetail_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.MessageBox.Show("Not implicated");
        } 
        #endregion

        /// <summary>
        /// 独立线程中，需要一个死循环，占据了 cpu 100%。 有什么更好的办法吗？
        /// </summary>
        private void mm_AnsyMonitor()
        {
           // while (true)
            //{
            //    try
            //    {
            //        if (me_PolipStatus == Enum_ProcessStauts.Running || me_TunnelStatus == Enum_ProcessStauts.Running)
            //        {
            //            if (mp_Polipo.HasExited)
            //            {
            //                me_PolipStatus = Enum_ProcessStauts.Stopped;
            //            }
            //            if (mp_Tunnel.HasExited)
            //            {
            //                me_TunnelStatus = Enum_ProcessStauts.Stopped;
            //            }
            //            mm_UpdateUi();  //  更新到界面
            //        }
                  
            //    }
            //    catch (Exception)
            //    {

            //        //throw;
            //    }
            //}
        }

        /// <summary>
        /// 即使下面的代码在独立的线程中，也需要定时器。有什么更好的办法吗？
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tmrMain_Tick_1(object sender, EventArgs e)
        {
            if (me_PolipStatus == Enum_ProcessStauts.Running  || me_TunnelStatus == Enum_ProcessStauts.Running )
            {
                if (mp_Polipo.HasExited)
                {
                    me_PolipStatus = Enum_ProcessStauts.Stopped;
                }
                if (mp_Tunnel.HasExited)
                {
                    me_TunnelStatus = Enum_ProcessStauts.Stopped;
                }
                mm_UpdateUi();  //  更新到界面
            }
        }
    }
}
